package com.lingmeng.system.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.lingmeng.common.core.constant.CacheConstants;
import com.lingmeng.common.core.exception.LingmengException;
import com.lingmeng.common.core.exception.ServiceException;
import com.lingmeng.common.core.utils.LocalDateTimeUtils;
import com.lingmeng.common.core.utils.uuid.UUID;
import com.lingmeng.common.redis.service.RedisService;
import com.lingmeng.system.entity.Equipment;
import com.lingmeng.system.mapper.EquipmentMapper;
import com.lingmeng.system.mapper.SysUserMapper;
import com.lingmeng.system.service.IEquipmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 设备Service业务层处理
 *
 * @author lingmeng
 * @date 2024-07-18
 */
@Service
@Slf4j
public class EquipmentServiceImpl implements IEquipmentService {
	@Autowired
	private EquipmentMapper equipmentMapper;
	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private RedisService redisService;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	/**
	 * 查询设备
	 *
	 * @param id 设备主键
	 * @return 设备
	 */
	@Override
	public Equipment selectEquipmentById(Long id) {
		return equipmentMapper.selectEquipmentById(id);
	}

	/**
	 * 查询设备列表
	 *
	 * @param equipment 设备
	 * @return 设备
	 */
	@Override
	public List<Equipment> selectEquipmentList(Equipment equipment) {
		return equipmentMapper.selectEquipmentList(equipment);
	}

	/**
	 * 新增设备
	 *
	 * @param equipment 设备
	 * @return 结果
	 */
	@Override
	@Transactional
	public int insertEquipment(Equipment equipment) {
		return equipmentMapper.insertEquipment(equipment);
	}

	/**
	 * 修改设备
	 *
	 * @param equipment 设备
	 * @return 结果
	 */
	@Override
	@Transactional
	public int updateEquipment(Equipment equipment) {
		return equipmentMapper.updateEquipment(equipment);
	}

	/**
	 * 批量删除设备
	 *
	 * @param ids 需要删除的设备主键
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteEquipmentByIds(Long[] ids) {
		return equipmentMapper.deleteEquipmentByIds(ids);
	}

	/**
	 * 删除设备信息
	 *
	 * @param id 设备主键
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteEquipmentById(Long id) {
		return equipmentMapper.deleteEquipmentById(id);
	}

	@Override
	@Transactional
	public void on(Long id) {
		Equipment equipment = equipmentMapper.selectEquipmentById(id);
		if (equipment == null) throw new LingmengException("设备不存在");
		if (equipment.getStatus() != 1) throw new LingmengException("设备暂时不能使用");
		if (equipment.getOnline().equals("1")) return;
		Equipment update = new Equipment();
		update.setOnline("1")
				.setId(id);
		equipmentMapper.updateEquipment(update);
		// TODO: 2024/7/18 新增开机时间戳到redis, 统计开机时长
		redisService.setCacheMapValue(CacheConstants.BUS_EQUIPMENT_RUNTIME_KEY, id+"", System.currentTimeMillis());
	}

	@Override
	@Transactional
	public void off(Long id) {
		Equipment equipment = equipmentMapper.selectEquipmentById(id);
		if (equipment == null) throw new LingmengException("设备不存在");
		if (equipment.getStatus() != 1) throw new LingmengException("设备暂时不能使用");
		if (equipment.getOnline().equals("0")) return;
		Object o = redisService.getCacheMapValue(CacheConstants.BUS_EQUIPMENT_RUNTIME_KEY, id+"");
		Equipment update = new Equipment();
		update.setOnline("0")
				.setId(id);
		if (o != null) {
			long l = System.currentTimeMillis() - Long.parseLong(o.toString());
			update.setRuntimeCount((l + equipment.getRuntimeCount())/1000);
		}
		equipmentMapper.updateEquipment(update);
	}

	@Override
	@Transactional
	public void activation(Long id, Long userId) {
		Equipment e = equipmentMapper.selectEquipmentById(id);
		if (e == null) throw new LingmengException("设备不存在");
		if (e.getStatus() == -1) throw new LingmengException("设备已经损坏");
		if (e.getStatus() != 0) throw new LingmengException("设备已经激活");

		String serialNum = e.getSerialNum();
		LocalDateTime now = LocalDateTime.now();
		long timestamp = LocalDateTimeUtils.localDateTimeToTimestamp(now);
		String code = SecureUtil.sha256(serialNum + timestamp).toUpperCase();
		Equipment update = new Equipment();
		update.setId(id)
				.setActivationCode(code)
				.setActivationTime(now)
				.setUserId(userId)
				.setStatus(1);
		equipmentMapper.updateEquipment(e);
	}

	@Override
	public String importEquip(List<Equipment> list, String operName) {
		if (list.isEmpty()) throw new LingmengException("导入数据不能为空");
		int successNum = 0;
		int failureNum = 0;
		StringBuilder successMsg = new StringBuilder();
		StringBuilder failureMsg = new StringBuilder();
		LocalDateTime dateTime = LocalDateTime.now();
		LocalDate date = dateTime.toLocalDate();
		for (Equipment equipment : list) {
			String mac = equipment.getMac();
			try {
				if (equipmentMapper.selectExitByMac(mac)) {
					failureNum++;
					failureMsg.append("<br/>")
							.append(mac)
							.append(" 已存在");
				} else {
					String serialNum = "LM" + UUID.randomUUID().toString().toUpperCase();
					equipment.insertClean()
							.setSerialNum(serialNum)
							.setManufactureDate(date)
							.setCreateBy(operName)
							.setCreateTime(dateTime);
					equipmentMapper.insertEquipment(equipment);
					successNum++;
					successMsg.append("<br/>")
							.append(mac)
							.append(" 导入成功");
				}
			} catch (Exception e) {
				failureNum++;
				String msg = "<br/>" + mac + " 导入失败";
				failureMsg.append(msg)
						.append(e.getMessage());
				log.error(msg, e);
			}
		}
		if (failureNum == 0) {
			successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
			return successMsg.toString();
		}
		failureMsg.insert(0, successNum + " 条导入成功，" + failureNum + " 条导入失败！错误如下：");
		throw new ServiceException(failureMsg.toString());
	}

}
